pub mod cmd;

use async_channel::{Receiver, Sender};
use base::{
    base::{Base, VBase, VMap},
    client::Client,
    err, err_value, ok, throw_err, ECode, MapSv, RNull, Resp, VecV,
};
use serde_json::{json, Value};
use std::sync::Arc;
use std::time::Instant;
use tokio::sync::Mutex;
use tracing::{instrument, warn};
use warp::{
    hyper::body::Bytes,
    reject::Rejection,
    reply::{Json, WithStatus},
};

pub use cmd::queue_job;

pub type VSend = Sender<Value>;
pub type VRece = Receiver<Value>;
pub type Lock = Arc<Mutex<()>>;

#[instrument(skip_all, name = "do_cmd")]
pub async fn do_cmd(
    data: Bytes,
    cmd: String,
    key: String,
    client: &Client,
    tx: VSend,
    lock: Lock,
) -> Result<WithStatus<Json>, Rejection> {
    let val = match base::do_byte(data) {
        Ok(v) => v,
        Err(e) => {
            warn!("error val: {:?} - {:?} - {:?}", &e, key, cmd);

            return Ok(base::ret_err(&e, None));
        }
    };

    let start = Instant::now();

    match cmd::doit(&val, &cmd, &key, client, tx, lock).await {
        Ok(v) => {
            let duration = start.elapsed();
            warn!(
                "dt: {:?} - end url: {:?} - cmd: {:?} - para: {:?}",
                duration, cmd, key, val
            );

            Ok(base::ret_ok(&v))
        }
        Err(e) => {
            let duration = start.elapsed();
            warn!(
                "dt: {:?} - error: {:?} - url: {:?} - cmd: {:?} - para: {:?}",
                duration, &e, cmd, key, val
            );

            Ok(base::ret_err(&e, None))
        }
    }
}

pub fn get_dir() -> String {
    if cfg!(windows) {
        "./files/".to_string()
    } else {
        "/files/".to_string()
    }
}
